﻿
#region Using directives

using System;

using Weazel.Badger.Vhdl;
using Weazel.Badger.Vhdl.Types;
using Weazel.Badger.Vhdl.Operators;
using Weazel.Badger.Vhdl.Statements;
using Weazel.Badger.Vhdl.Expressions;

#endregion

namespace Weazel.Badger
{
  public class SynthesisSystemEntity : SystemEntity
  {
    private Port clockPort;
    private Port resetPort;

    public SynthesisSystemEntity(ConversionContext context, Gezel.Model.Model model, Gezel.Model.system system)
      : base(context, model, system)
    {		
			resetPort = new Port(new StdLogic(), null, context.Configuration.ResetName, PortDirection.In, -1);
    }

    public void Convert()
    {
      CreateSignals();

      if (context.Configuration.DivideClock)
      {
        // note: this code can only split the clock by 2

        // create a new clock port to be used on the top level (before division)
        clockPort = 
          new Port(
            new StdLogic(), 
            null, 
            context.Configuration.TopLevelClockName, 
            PortDirection.In, 
            -1
          );
        
        AddPort(clockPort);    
 
        // add an inner clock signal (after division)
        Signal clockSignal = 
          new Signal(
            new StdLogic(), 
            null, 
            context.Configuration.ClockName
          );
        
        AddSignal(clockSignal);
        AddDeclarativeItem(clockSignal);    

        Process clockDivisionProcess =
          Predefined.ClockDivisionProcess.Get(
            this,
            clockPort,
            clockSignal
          );

        AddProcess(clockDivisionProcess);

        System.Windows.Forms.MessageBox.Show("process added");
      }
      else
      {
        clockPort =
          new Port(
            new StdLogic(),
            null,
            context.Configuration.ClockName,
            PortDirection.In,
            -1
          );

        clockPort.Type = new StdLogic();
        AddPort(clockPort);      
      }      

      resetPort.Type = new StdLogic();
      AddPort(resetPort);    

      CreateComponentDeclarations(clockPort, resetPort);
      CreatePortMaps(clockPort, resetPort);
    }

    protected override void OnUnconnectedInputNetFound(Weazel.Gezel.Model.system.Net net)
    {
      System.Diagnostics.Debug.Assert(net.OutPort != null);

      Vhdl.Types.Type t = net.OutPort.Width == 1 ?
          (Vhdl.Types.Type) new StdLogic()
        : (Vhdl.Types.Type) new StdLogicVector(net.OutPort.Width);

      Port port = new Port(t, new Vhdl.GezelType(net.OutPort.Signed, net.OutPort.Width), net.LocalName, PortDirection.Out, -1);

      AddPort(port);
    }

    protected override void OnUnconnectedOutputNetFound(Weazel.Gezel.Model.system.Net net)
    {
      System.Diagnostics.Debug.Assert(net.InPorts != null);
      System.Diagnostics.Debug.Assert(net.InPorts.Count > 0);

      int maxWidth = 0;
      foreach (Gezel.Model.InPort inport in net.InPorts)
        if (inport.Width > maxWidth)
          maxWidth = inport.Width;

      Vhdl.Types.Type t = maxWidth == 1 ?
          (Vhdl.Types.Type)new StdLogic()
        : (Vhdl.Types.Type)new StdLogicVector(maxWidth);

      Port port = new Port(t, new Vhdl.GezelType(net.InPorts[0].Signed, maxWidth), net.LocalName, PortDirection.In, -1);

      AddPort(port);
    }
  }
}
